package com.nowcoder.topic.pointers.middle;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;

/**
 * NC348 四数之和
 * @author d3y1
 */
public class NC348{
    /**
     * 代码中的类名、方法名、参数名已经指定，请勿修改，直接返回方法规定的值即可
     *
     * 相似 -> NC247 最接近的三数之和 [nowcoder]
     * 相似 -> NC275 和为S的两个数字 [nowcoder]
     *
     * @param nums int整型ArrayList
     * @param target int整型
     * @return int整型ArrayList<ArrayList<>>
     */
    public ArrayList<ArrayList<Integer>> fournumber (ArrayList<Integer> nums, int target) {
        // return solution1(nums, target);
        return solution2(nums, target);
        // return solution3(nums, target);
    }

    /**
     * 排序+四指针(固二动二)
     * @param nums
     * @param target
     * @return
     */
    private ArrayList<ArrayList<Integer>> solution1(ArrayList<Integer> nums, int target){
        int n = nums.size();

        // 排序
        Collections.sort(nums);

        ArrayList<ArrayList<Integer>> result = new ArrayList<>();
        ArrayList<Integer> list;
        HashSet<ArrayList<Integer>> set = new HashSet<>();

        int p,q;
        int sum;
        // 固二: i j
        for(int i=0; i<n; i++){
            for(int j=i+1; j<n; j++){
                p = j+1;
                q = n-1;
                // 动二: p q
                while(p < q){
                    sum = nums.get(i)+nums.get(j)+nums.get(p)+nums.get(q);
                    if(sum < target){
                        p++;
                    }else if(sum > target){
                        q--;
                    }else{
                        list = new ArrayList<>();
                        list.add(nums.get(i));
                        list.add(nums.get(j));
                        list.add(nums.get(p));
                        list.add(nums.get(q));
                        // 去重
                        set.add(list);
                        // 去重
                        while(++p < q){
                            if(!nums.get(p).equals(nums.get(p-1))){
                                break;
                            }
                        }
                        // 去重
                        while(p < --q){
                            if(!nums.get(q).equals(nums.get(q+1))){
                                break;
                            }
                        }
                    }
                }
            }
        }

        result.addAll(set);

        return result;
    }

    /**
     * 排序+四指针(固二动二)
     * @param nums
     * @param target
     * @return
     */
    private ArrayList<ArrayList<Integer>> solution2(ArrayList<Integer> nums, int target){
        int n = nums.size();

        // 排序
        Collections.sort(nums);

        ArrayList<ArrayList<Integer>> result = new ArrayList<>();
        ArrayList<Integer> list;

        int p,q;
        int sum;
        // 固二: i j
        for(int i=0; i<n; i++){
            // 去重
            if(i>0 && nums.get(i).equals(nums.get(i-1))){
                continue;
            }
            for(int j=i+1; j<n; j++){
                // 去重
                if(j>i+1 && nums.get(j).equals(nums.get(j-1))){
                    continue;
                }
                p = j+1;
                q = n-1;
                // 动二: p q
                while(p < q){
                    sum = nums.get(i)+nums.get(j)+nums.get(p)+nums.get(q);
                    if(sum < target){
                        p++;
                    }else if(sum > target){
                        q--;
                    }else{
                        list = new ArrayList<>();
                        list.add(nums.get(i));
                        list.add(nums.get(j));
                        list.add(nums.get(p));
                        list.add(nums.get(q));
                        result.add(list);
                        // 去重
                        while(++p < q){
                            if(!nums.get(p).equals(nums.get(p-1))){
                                break;
                            }
                        }
                        // 去重
                        while(p < --q){
                            if(!nums.get(q).equals(nums.get(q+1))){
                                break;
                            }
                        }
                    }
                }
            }
        }

        return result;
    }

    /**
     * 排序+四指针(固二动二)
     * @param nums
     * @param target
     * @return
     */
    private ArrayList<ArrayList<Integer>> solution3(ArrayList<Integer> nums, int target){
        int n = nums.size();

        // 排序
        Collections.sort(nums);

        ArrayList<ArrayList<Integer>> result = new ArrayList<>();
        ArrayList<Integer> list;

        int p,q;
        int sum;
        // 固二: i j
        for(int i=0; i<n; i++){
            // 去重
            if(i>0 && nums.get(i).equals(nums.get(i-1))){
                continue;
            }
            for(int j=i+1; j<n; j++){
                // 去重
                if(j>i+1 && nums.get(j).equals(nums.get(j-1))){
                    continue;
                }
                p = j+1;
                q = n-1;
                // 动二: p q
                while(p < q){
                    // 去重
                    while(p>j+1 && p<n && nums.get(p).equals(nums.get(p-1))){
                        p++;
                    }
                    if(p >= q){
                        break;
                    }
                    sum = nums.get(i)+nums.get(j)+nums.get(p)+nums.get(q);
                    if(sum < target){
                        p++;
                    }else if(sum > target){
                        q--;
                    }else{
                        list = new ArrayList<>();
                        list.add(nums.get(i));
                        list.add(nums.get(j));
                        list.add(nums.get(p));
                        list.add(nums.get(q));
                        result.add(list);
                        p++;
                    }
                }
            }
        }

        return result;
    }
}